#include "Quaternion.h"
using namespace std;

//Prints the type and the 4 fields
void Quaternion::print( std::ostream& out ) const
{
	out << typeid(*this).name() << " x:" << x << ", y:" << y << ", z:" << z << ", w:" << w;
}

//Creates a quaternion with fields of 0
Quaternion::Quaternion( void )
{ 
	x = 0;
	y = 0;
	z = 0;
	w = 0;
}

//Creates a quaternion with fields of X, Y, Z, and W
Quaternion::Quaternion( double X,double Y,double Z,double W ) : x(X),y(Y),z(Z),w(W) { }

//Copy constructor
Quaternion::Quaternion( const Quaternion& other )
{
	x = other.x;
	y = other.y;
	z = other.z;
	w = other.w;
}

//Conversion Constructor from Scalar
Quaternion::Quaternion( double in ) : x(in)
{
	y = 0;
	z = 0;
	w = 0;
}

//Conversion Constructor from Vector
Quaternion::Quaternion( Vector3D in )
{
	x = in.getX();
	y = in.getY();
	z = in.getZ();
	w = 0;
}

//Copy assignment operator
Quaternion& Quaternion::operator=( const Quaternion& other )
{
	this->x = other.x;
	this->y = other.y;
	this->z = other.z;
	this->w = other.w;
	return *this;
}

//Adds two quaternions
Quaternion& Quaternion::operator+( const Quaternion& other )
{
	return Quaternion(x + other.x,y + other.y,z + other.z,w + other.w);
}

//Subtracts two quaternions
Quaternion& Quaternion::operator-( const Quaternion& other )
{
	return Quaternion(x - other.x,y - other.y,z - other.z,w - other.w);
}

//Dot product of 2 quaternions
Quaternion& Quaternion::operator*( const Quaternion& other )
{
	//YAY COMPLICATED MATHS
	double newX = (x*other.w) + (w*other.x) + (y*other.z) - (z*other.y);
	double newY = (y*other.w) + (w*other.y) + (z*other.x) - (x*other.z);
	double newZ = (z*other.w) + (w*other.z) + (x*other.y) - (y*other.x);
	double newW = (w*other.w) - (x*other.x) - (y*other.y) - (z*other.z);
	return Quaternion(newX,newY,newZ,newW);
} 

//Multiplies a quaternion by a scalar
Quaternion& Quaternion::operator*=( double in )
{
	return Quaternion(x*in,y*in,z*in,w*in);
}

//Returns the conjugate of the quaternion
Quaternion& Quaternion::operator!()
{
	return Quaternion(-x,-y,-z,w);
}

//Returns the negative of the quaternion
Quaternion& Quaternion::operator-( void )
{
	return Quaternion(-x,-y,-z,-w);
}

//overloading the << operator to call print
ostream& operator<<(ostream& out, const Quaternion& q) 
{
	q.print(out);
	return out;
}

//Garbage collection
Quaternion::~Quaternion( void )
{

}